﻿// ******************************************************************************
// Developed by Oguz Demirel
// Date: April 5, 2010
// ******************************************************************************
using System;
using System.Net;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.ApplicationPages;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using System.Collections;
using System.IO;

namespace BulkListActions
{
    public partial class Move : LayoutsPageBase
    {
        #region ..:: FIELDS ::..
        private const string MAIN_TABLE_ID = "tblMain";
        private const string LABEL = "lbl{0}";
        private const string FIELD = "fld{0}";
        private const string CHECK = "cb{0}";
        private const string DROPDOWN = "ddl{0}";
        private const string LABEL_CSS = "ms-formlabel";
        private const string FIELD_CSS = "ms-formbody";

        string[] IDs;
        ArrayList CTNames = new ArrayList();
        string listID;
        string referrer;
        string webID;
        string webUrl;
        string listUrl;

        #endregion ..:: FIELDS ::..

        //protected override SPBasePermissions RightsRequired
        //{
        //    get
        //    {
        //        SPBasePermissions permissions = base.RightsRequired
        //            | SPBasePermissions.AddListItems
        //            | SPBasePermissions.DeleteListItems
        //            //| SPBasePermissions.ManageLists
        //            ;
        //        return permissions;
        //    }
        //}

        //protected override bool RequireDefaultLayoutsRights 
        //{ get {return false;} }

        //public Move() { this.RightsCheckMode = RightsCheckModes.OnPreInit; }

        #region ..:: PAGE EVENTS ::..
        protected override void OnInit(EventArgs e)
        {
            // Get query string values
            string qsItemIDs = Request.QueryString["IDs"];
            listID = Request.QueryString["ListID"];
            referrer = Request.QueryString["referrer"];

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                // Find web ID and url of referrer web
                using (SPSite site = new SPSite(referrer))
                {
                    SPWebCollection webs = site.AllWebs;
                    foreach (SPWeb webObj in webs)
                        if (webObj.Url == referrer)
                        {
                            webID = webObj.ID.ToString();
                            webUrl = webObj.Url;
                            listUrl = webObj.Lists[new Guid(listID)].DefaultViewUrl;
                            break;
                        }
                } // end - using
            });

            // Get selected item IDs
            IDs = qsItemIDs.Split(new char[] { '_' });
            
            // Check if IDs exist
            using (SPSite site = new SPSite(referrer))
            using (SPWeb web = site.OpenWeb(new Guid(webID)))
            {
                SPList list = web.Lists[new Guid(listID)];
                foreach (string id in IDs)
                    try
                    {
                        SPListItem itemByID = list.GetItemByUniqueId(new Guid(id));
                        if (itemByID != null)
                        {
                            // Store CT IDs in an array list
                            CTNames.Add(itemByID.ContentType.Name);
                            continue;
                        }

                    }
                    catch
                    {
                        SPUtility.TransferToErrorPage("List item doesn't exist. {0} {1}", "Click here to go back to the list.", referrer);
                    }
            } // end - using

        }

        protected override void OnLoad(EventArgs e)
        {

            //**************************************** 
            // Validate the page request to avoid 
            // any malicious posts 
            if (Request.HttpMethod == "POST")
                SPUtility.ValidateFormDigest();

            //**************************************** 
            // Validate the page request to avoid 
            // any malicious posts 
            if (Request.HttpMethod == "POST")
                SPUtility.ValidateFormDigest();

            //****************************************
            // Initialize the controls on the page
            // if its not a PostBack request
            if (!(Page.IsPostBack))
            {
                using (SPSite site = new SPSite(referrer))
                using (SPWeb web = site.OpenWeb(new Guid(webID)))
                {
                    foreach (SPList list in web.Lists)
                    {
                        // Determine if this list is a document library or not
                        if (list.BaseType == SPBaseType.DocumentLibrary && !list.Hidden)
                            // Add document library names to destination ddl
                            ddlDestination.Items.Add(list.Title);

                    }
                    
                } // end - using

            } // end - ! IsPostPack 

        }

        //*************************************************************
        // This method is called when the user clicks the "OK" button
        protected void BtnSubmit_Click(object sender, EventArgs e)
        {
            try
            {
                using (SPSite site = new SPSite(referrer))
                using (SPWeb web = site.OpenWeb(new Guid(webID)))
                {
                    // Get source list
                    SPList srcList = web.Lists[new Guid(listID)];
                    // Get destination list
                    SPList destList = web.Lists[ddlDestination.SelectedValue];

                    // First, check permissions if user can move documents to 
                    // destination library or not
                    if (destList.DoesUserHavePermissions(SPBasePermissions.AddListItems) &&
                        destList.DoesUserHavePermissions(SPBasePermissions.EditListItems) &&
                        srcList.DoesUserHavePermissions(SPBasePermissions.DeleteListItems) )
                    {
                        // Prepare destination library before move operation
                        // Check for existing CTs and selected documents CTs
                        // Add missing ones if there are any
                        AddMissingContentTypesToList();

                        // Ready to move documents since now CTs exist
                        // in destination library.
                        // Perform move operation
                        MoveItems(srcList, destList);

                    } // end - if
                    else
                        SPUtility.TransferToErrorPage("You don't have sufficient rights to move documents. {0} {1}", "Click here to go back to the list.", referrer);
                } // end - using - web

                // Redirect back to list after moving documents
                Response.Redirect(listUrl);

            } // end - try
            catch (ThreadAbortException x)
            { // Do nothing 
            }
            catch (Exception ex)
            {
                // if an error occurs, capture the message to display it to the user
                SPUtility.TransferToErrorPage(ex.Message + " {0} {1}", "Click here to go back to the list.", referrer);
            }

        } // end - BtnSubmit_Click

        //*************************************************************
        // This method is called when the user clicks the "Cancel" button
        protected void BtnCancel_Click(object sender, EventArgs e)
        {
            // Redirect back to list
            Response.Redirect(listUrl);
        }
        #endregion ..:: PAGE EVENTS ::..

        #region ..:: PRIVATE METHODS ::..
        //*************************************************************
        // This method checks for existing CTs and selected documents CTs
        // Adds missing ones - if there are any - to destination list
        private void AddMissingContentTypesToList()
        {
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(referrer))
                using (SPWeb web = site.OpenWeb(new Guid(webID)))
                {
                    // Get destination list
                    SPList list = web.Lists[ddlDestination.SelectedValue];

                    // Check if CTs enabled
                    if (list.ContentTypesEnabled)
                    {
                        // Check for existing CTs and selected documents CTs
                        // Add missing ones if there are any

                        // Store existing CT names of destination library
                        ArrayList destinationListCTNames = new ArrayList();

                        // Loop for each CT of selected documents
                        foreach (string ctName in CTNames)
                        {
                            // Construct a fresh list for
                            // destination list CT names
                            destinationListCTNames.Clear();
                            foreach (SPContentType ct in list.ContentTypes)
                                destinationListCTNames.Add(ct.Name);

                            if (destinationListCTNames.Contains(ctName))
                                continue;
                            else
                            // Add missing CT
                            {
                                SPContentType ctToBeAdded = web.ContentTypes[ctName];
                                list.ContentTypes.Add(ctToBeAdded);

                            } // end - else

                        } // end - foreach

                        // Save changes for the list
                        list.Update();

                    } // end - if
                    else
                    {
                        // CTs not enabled. Enable it
                        list.ContentTypesEnabled = true;
                        list.Update();

                        // Call self one more time
                        AddMissingContentTypesToList();

                    } // end - else

                } // end - using

            }); // end - elevated

            } // end - try
            catch
            {
                SPUtility.TransferToErrorPage("Can not add content types to destination library. {0} {1}", "Click here to go back to the list.", referrer);
            }
        
        }

        //*************************************************************
        // This method moves items from source list to destination list
        private void MoveItems(SPList srcList, SPList destList)
        {
            // Move selected items from source to destination list
            foreach (string id in IDs)
            {
                Guid selectedItemID = new Guid(id);

                // Get item
                SPListItem item = srcList.GetItemByUniqueId(selectedItemID);
                
                // Copy item to destination
                // Note: SPListItem.CopyTo doesn't work properly.
                // Another CopyItem method is provided as a private method
                CopyFile(item, destList.Title);

                // Delete item
                item.Delete();
                
            } // end - foreach
        }

        public void CopyFile(SPListItem sourceItem, string destinationListName)
        {
            try
            {
                //copy sourceItem to destinationList
                SPList destinationList = sourceItem.Web.Lists[destinationListName];

                // Get file
                SPFile fileToCopy = sourceItem.File;

                // Open file
                byte[] fileData = fileToCopy.OpenBinary();
                const bool OverwriteDestinationFile = true;
                string relativeDestinationUrl = destinationList.RootFolder.Url + "/" + sourceItem.File.Name;

                // Add file to destination list
                SPFile destinationFile = ((SPDocumentLibrary)destinationList).RootFolder.Files.Add(relativeDestinationUrl, fileData, OverwriteDestinationFile);
                SPListItem targetItem = destinationFile.Item;

                // Grab the content type from the list so we can get the id
                SPContentType ct = destinationList.ParentWeb.ContentTypes[sourceItem.ContentType.Name];

                // Update content type of target item
                targetItem["ContentTypeId"] = ct.Id;
                targetItem.Update();

                // now we have access to set all the content type fields
                foreach (SPField f in sourceItem.Fields)
                {
                    // Check if field exists or not
                    if (targetItem.Fields.ContainsField(f.InternalName))
                        if (!f.ReadOnlyField && f.InternalName != "Attachments")
                        {
                            targetItem[f.InternalName] = sourceItem[f.InternalName];
                        }
                }
                // Save changes
                targetItem.Update();

                // Check-in item if required
                if (destinationList.ForceCheckout)
                    targetItem.File.CheckIn("Moved from library: " + sourceItem.ParentList.Title);
            }
            catch(SPException ex)
            {
                // If destination list forces check-out, overwriting document can fail here
                SPUtility.TransferToErrorPage("Can not copy file(s) to destination library." + ex.Message
                    + " {0} {1}", "Click here to go back to the list.", referrer);
            }

        } // end - CopyFile


        
        #endregion ..:: PRIVATE METHODS ::..

    }
}
